package core.bmp.worker.filter;

import java.io.File;

import core.bmp.AbsWorker;
import core.bmp.Bmp;
import core.bmp.model.BmpData;
import core.bmp.model.Pixel;
import core.bmp.utils.IntegerUtil;
import core.bmp.utils.PixelUtil;

/**
 * 直方图规定化
 * 
 * @author DrkCore
 * @since 2015年11月30日23:24:33
 */
public class SpecificationWorker extends AbsWorker {

	/* 继承 */

	@Override
	protected File onPrepareImageFile() {
		return Bmp.BMP_GRAY;
	}

	@Override
	public void onWork(BmpData bmpData) {
		int[] argb = bmpData.getArgbPix();
		// 获取每个颜色分量的长度
		int colorCount = 0x1 << (bmpData.getColorBit() / 3);

		// 统计灰度个数
		int[] grays = statisticsGrayCount(colorCount, argb);

		// 获取累积直方图
		float[] grayProb = accumulateGrayPossibility(argb.length, colorCount, grays);

		// 给出规定直方图以及其累积
		int[] targetProbIndex = new int[] { 50, 100, 150, 200, 255 };
		float[] targetProbValue = new float[] { 0.3F, 0.25F, 0.2F, 0.2F, 0.05F };
		float[] accmulateTargetProbValue = new float[] { 0.3F, 0.55F, 0.75F, 0.95F, 1.0F };

		// 计算SML映射
		int[] smlMap = new int[colorCount];
		for (int i = 0; i < colorCount; i++) {
			float curGrayProb = grayProb[i];
			// 计算最靠近的那个概率
			float minValue = Math.abs(curGrayProb - accmulateTargetProbValue[0]);
			int minIndex = 0;
			for (int j = 1, len = accmulateTargetProbValue.length; j < len; j++) {
				float tmp = Math.abs(curGrayProb - accmulateTargetProbValue[j]);
				if (minValue > tmp) {
					minValue = tmp;
					minIndex = j;
				}
			}
			grayProb[i] = targetProbValue[minIndex];
			smlMap[i] = targetProbIndex[minIndex];
		}

		// 应用变换
		Pixel pixel;
		for (int i = 0, size = argb.length; i < size; i++) {
			pixel = PixelUtil.intToPixel(argb[i]);
			byte gray = pixel.getRed();
			int idx = IntegerUtil.byteToUnsignedInt(gray);
			PixelUtil.setGray(pixel, (byte) smlMap[idx]);
			argb[i] = PixelUtil.pixelToInt(pixel);

		}
	}

	/* 拓展 */

	/**
	 * 统计像素个数
	 * 
	 * @param colorCount
	 * @param argb
	 * @return
	 */
	private int[] statisticsGrayCount(int colorCount, int[] argb) {
		int[] grays = new int[colorCount];
		int gray;
		for (int i = 0, len = argb.length; i < len; i++) {
			gray = argb[i] & 0x000000FF;
			grays[gray]++;
		}
		return grays;
	}

	/**
	 * 获取累积直方图
	 * 
	 * @param size
	 * @param colorCount
	 * @param grays
	 * @return
	 */
	private float[] accumulateGrayPossibility(int size, int colorCount, int[] grays) {
		float[] grayProb = new float[colorCount];
		int lastCount = 0;
		float fSize = size;
		for (int i = 0; i < colorCount; i++) {
			lastCount += grays[i];
			grayProb[i] = lastCount / fSize;
		}
		return grayProb;
	}

}
